#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#pragma pack(push, 1)
typedef struct msg_hrd_s {
    uint8_t  type;
    uint32_t len;
} msg_hrd_t;

typedef struct msg_s {
    msg_hrd_t header;
    char *body;
} msg_t;
#pragma pack(pop)

msg_t *msg_new(uint8_t type) {
    msg_t *msg = malloc(sizeof(msg_t));
    msg->header.type = type;
    return msg;
}

void msg_free(msg_t **pmsg) {
    if (*pmsg) free(*pmsg);
    pmsg = NULL;
}

msg_t *msg_create(uint8_t type, char *data, uint32_t len) {
   msg_t *msg = msg_new(type);
   msg->header.len = len;
   memcpy(msg->body, data, msg->header.len);

   return msg;
}

char *msg_stream(msg_t *msg) {
   return (char *)msg;
}

uint32_t msg_len(msg_t *msg) {
    return sizeof(msg_hrd_t) + msg->header.len;
}

msg_t *msg_parse(void *stream, uint32_t len) {
   msg_t *msg = msg_new(0);

   memcpy(&(msg->header), stream, sizeof(msg_hrd_t));

   msg->body = malloc(sizeof(msg->header.len));
   memcpy(msg->body, stream + sizeof(msg_hrd_t), msg->header.len);

   return msg;
}

void msg_print(msg_t *msg) {
    if (msg->header.len < 65536) {
        char body[msg->header.len + 1];
        memcpy(body, msg->body, msg->header.len);
        memset(body + msg->header.len, '\0', 1);
        printf("Message(t:%d,body:%d):%s\n", msg->header.type, msg->header.len, body);
    } else {
        printf("Message(%d,%d):too long\n", msg->header.type, msg->header.len);
    }
}

int main() {
    char *data = "abcdefghijklmnopqrstuvwxyz";
    msg_t msg = { { .type = 2, .len = strlen(data) }, .body=data };
    uint32_t mlen = msg_len(&msg);
    printf("msg length: %d, size: %ld\n", mlen, sizeof(msg_hrd_t));
    msg_print(&msg);

    char *p = (char *)&msg;
    char stream[mlen];

    memset(stream, '\0', mlen);
    memcpy(stream, p, sizeof(msg_hrd_t));
    memcpy(stream + sizeof(msg_hrd_t), msg.body, mlen);

    msg_t *msg2 = msg_parse(stream, mlen);
    msg_print(msg2);

    msg_free(&msg2);

    return 0;
}
